package com.maslyk.invitation.service;

import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.springframework.transaction.annotation.Transactional;

import com.maslyk.invitation.entitybean.Attachment;
import com.maslyk.invitation.entitybean.Auditlog;
import com.maslyk.invitation.entitybean.Client;
import com.maslyk.invitation.entitybean.Comment;
import com.maslyk.invitation.entitybean.FeeInvitation;
import com.maslyk.invitation.entitybean.Insertion;
import com.maslyk.invitation.entitybean.Invitation;
import com.maslyk.invitation.entitybean.Order;
import com.maslyk.invitation.entitybean.Payment;
import com.maslyk.invitation.entitybean.Person;
import com.maslyk.invitation.entitybean.PriceParameter;
import com.maslyk.invitation.entitybean.Product;
import com.maslyk.invitation.entitybean.Salesman;
import com.maslyk.invitation.entitybean.Text;
import com.maslyk.invitation.entitybean.Vigniette;
import com.maslyk.invitation.entitybean.util.CloneUtil;
import com.maslyk.invitation.enums.RecordTypeEnum;
import com.maslyk.invitation.exception.LogicalException;
import com.maslyk.invitation.exception.SystemException;
import com.maslyk.invitation.service.email.MessagingEmailService;
import com.maslyk.invitation.to.AuditLogSearchCriteria;
import com.maslyk.invitation.to.ClientSearchCriteria;
import com.maslyk.invitation.to.OrderSearchCondition;


public class PersistenceService
{
	private Logger log = Logger.getLogger(PersistenceService.class);
	
	@PersistenceContext
	private EntityManager entityManager;
		 
	
	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

    public Person createPerson(Person personEntity)
    {
        return null;
    }

    @Transactional
    public Salesman createSalesman(Salesman salesmanEntity) throws LogicalException, SystemException
    {
        String passwd = salesmanEntity.getPassword();
        
        salesmanEntity.setPassword(MD5Service.generateHexString(salesmanEntity.getPassword()));
        entityManager.persist(salesmanEntity);

        StringBuffer message = new StringBuffer();
        message.append("<h2>"+salesmanEntity.getPersonid().getFirstname()+",</h2>");
        message.append("<h3>Za\u0142o\u017Cono Ci nowe konto w systemie rejestracji zam\u00f3wien  StudioGrafic</h3>");
        message.append("<h4>Nazwa u\u017Cytkownika (login): " + salesmanEntity.getLogin() + "</h4>");
        message.append("<h4>Has\u0142o do systemu to: " +passwd+"</h4>");
        message.append("<br /><br />");
        message.append("<i>Zapamietaj prosze te informacje.</i>");
        MessagingEmailService emailService = new MessagingEmailService();
        emailService.sendMessage(salesmanEntity.getPersonid().getEmail(), message.toString(), "Dodano nowego u\u017Cytkownika systemu");
        
        return salesmanEntity;
    }
    
    @Transactional
    public Salesman editSalesman(Salesman salesmanEntity) throws SystemException
    {
        salesmanEntity = entityManager.merge(salesmanEntity);
        return salesmanEntity;
    }

    @Transactional
    public void destroySalesman(Salesman salesmanEntity) throws SystemException
    {   
    	Salesman salesmanEntity1 = entityManager.getReference(Salesman.class, salesmanEntity.getId());
    	entityManager.remove(salesmanEntity1);
    }
    
    @Transactional
    public void removePriceParameter(PriceParameter priceParameter) throws SystemException
    {
    	PriceParameter priceParameterFound = entityManager.getReference(PriceParameter.class, priceParameter.getId());
        entityManager.remove(priceParameterFound);
    }
    
    public Order findOrderEntity(Integer id) throws SystemException
    {
    	try
    	{
    		return entityManager.find(Order.class, id);
    	}
    	catch(Exception ex)
    	{
    		throw new SystemException(ex);
    	}
    }

    @SuppressWarnings("unchecked")
	public List<Salesman> getSalesmanList() throws SystemException
    {
        try
        {
        	return entityManager.createQuery("select o from Salesman o order by o.personid.surname").getResultList();
        }
        catch(Exception ex)
        {
        	throw new SystemException(ex);
        }
    }
    
    @Transactional
    public Text createText(Text textEntity) throws SystemException
    {
        entityManager.persist(textEntity);
        return textEntity;
    }
    
    @Transactional
    public Attachment createAttachment(Attachment attachmentEntity) throws SystemException
    {
        entityManager.persist(attachmentEntity);
        return attachmentEntity;
    }
    
    @Transactional
    public Invitation saveInvitation(Invitation invitation) throws SystemException
    {      
    		if(invitation.getId() == null)
            	entityManager.persist(invitation);
            else
            	entityManager.merge(invitation);
        
    		return invitation;
    }
    
    @Transactional
    public void removeEntity(Object entity) throws SystemException
    {
    	entityManager.remove(entity);
    }

    @Transactional
    public PriceParameter savePriceParameter(PriceParameter priceParameterEntity) throws SystemException
    {
        if(priceParameterEntity.isInserted())
        	priceParameterEntity = entityManager.merge(priceParameterEntity);
        else
        	entityManager.persist(priceParameterEntity);
        
        return priceParameterEntity;
    }

    @Transactional
    public Text saveText(Text textEntity) throws SystemException
    {
        if(textEntity.isInserted())
        	entityManager.persist(textEntity);
        else
        	textEntity = entityManager.merge(textEntity);
        
        return textEntity;
    }

    @Transactional
    public PriceParameter updatePriceParameter(PriceParameter priceParameterEntity) throws SystemException
    {
    	priceParameterEntity = entityManager.merge(priceParameterEntity);
        return priceParameterEntity;
    }
    
    @Transactional
    public Invitation updateInvitation(Invitation inv) throws SystemException {

    	inv = entityManager.merge(inv);
        return inv;
    }
    
    @Transactional
    public FeeInvitation updateFeeInvitation(FeeInvitation fee) throws SystemException {

    	fee = entityManager.merge(fee);
        return fee;
    }
 
    @Transactional
	public void removeText(Text textEntity) throws SystemException
    {
        entityManager.remove(textEntity);
    }

    @Transactional
	public void removeFeeInvotation(FeeInvitation fee) throws SystemException
    {
        entityManager.remove(fee);
    }

	public List<Text> getTextList()
    {
        List<Text> texts = null;

        Query q = entityManager.createQuery("select object(o) from Text as o");
        texts = q.getResultList();

        return texts;
    }
    
	@SuppressWarnings("unchecked")
	public List<PriceParameter> getPriceParameterList()
    {
    	
        List<PriceParameter> priceParameterList = null;

        Query q = entityManager.createQuery("select o from PriceParameter as o");
        priceParameterList = q.getResultList();

        return priceParameterList;
    }
    
    @SuppressWarnings("unchecked")
	public List<Attachment> getAttachmentList(int position)
    {
    	
        List<Attachment> atts = null;

        Query q = entityManager.createQuery("select o from Attachment o");
        q.setFirstResult(position);
        q.setMaxResults(100);
        atts = q.getResultList();

        return atts;
    }

	@SuppressWarnings("unchecked")
	public List<Auditlog> getAuditList(AuditLogSearchCriteria auditCriteria)
    {
    	
        List<Auditlog> logs = null;

        Query q = entityManager.createQuery("select a from Auditlog a where a.operatorId = :operator and a.objectKey = :key and date(a.createdDate) between :from and :to order by a.entityId");
        q.setParameter("operator", auditCriteria.getSalesman());
        q.setParameter("key", auditCriteria.getSearchKey());
        q.setParameter("from", auditCriteria.getDateFrom());
        q.setParameter("to", auditCriteria.getDateTo());
        logs = q.getResultList();

        return logs;
    }

    public Text findTextEntity(Integer id)
    {
    	
    	return entityManager.find(Text.class, id);
    }

    public Salesman login(String login, String password)
    {
        Query qry = entityManager.createQuery("from Salesman salesman where salesman.login = :login and salesman.password = :password");
        qry.setParameter("login", login);
        qry.setParameter("password", MD5Service.generateHexString(password));

        Salesman logger = null;
        
        try
        {
        	logger = (Salesman) qry.getSingleResult();
        }
        catch (Throwable t)
        {
            log.error("Blad logowania operatora: ", t);
        	return null;
        }
        
        // nieaktywny nie moze sie zalogowac
        if(logger.isInactive())
        	return null;
        
        return logger;
    }

    @Transactional
    public Order saveOrder(Order order) throws SystemException
    {
    	order = entityManager.merge(order);
		return order;
    }

	@SuppressWarnings("unchecked")
	public List<Client> searchClient(ClientSearchCriteria condition)
    {
        Session session = (Session) entityManager.getDelegate();
        Criteria criteria = session.createCriteria(Client.class);

        if(condition.getName() == null &&
        	condition.getEmail() == null &&
        	condition.getPhone() == null &&
        	condition.getShippingAddress() == null)
        	return  null;
        
        if(condition.getName() != null)
            criteria.add(Restrictions.like("name", "%"+condition.getName()+"%"));
        
        if(condition.getEmail() != null)
            criteria.add(Restrictions.like("email", "%"+condition.getEmail()+"%"));
        
        if(condition.getPhone() != null)
            criteria.add(Restrictions.like("phone", "%"+condition.getPhone()+"%"));        

        if(condition.getShippingAddress() != null)
            criteria.add(Restrictions.like("shippingAddress", "%" + condition.getShippingAddress() + "%"));
        
        return (List<Client>)criteria.list();

    }
    
    
    @SuppressWarnings("unchecked")
    @Transactional
	public List<Order> searchOrders(OrderSearchCondition condition)
    {   
        Session session = (Session) entityManager.unwrap( Session.class );
        
        Criteria criteria = session.createCriteria(Order.class);
        
        if(!condition.isSearchInOffers())
        	criteria.add(Restrictions.eq("type", RecordTypeEnum.ORDER));

        if(condition.getNumber() != null)
            criteria.add(Restrictions.like("number", condition.getNumber()+"%"));

        Criteria clientCriteria = null;
        if(condition.getClientName() != null || condition.getEmail() != null)
        	clientCriteria = criteria.createCriteria("client");
        	
        if(condition.getClientName() != null)
        	clientCriteria.add(Restrictions.like("name", "%" + condition.getClientName() + "%"));

        if(condition.getEmail() != null)
        	clientCriteria.add(Restrictions.like("email", "%" + condition.getEmail() + "%"));

        Criteria invitationCriteria = null;

        if(condition.getBrideName() != null ||
           condition.getBrideGroom() != null ||
           condition.getWeddingpartyplace() != null ||
           condition.getWeddingplace() != null)
        {
            invitationCriteria = criteria.createCriteria("invitationEntityCollection");
        }

        if(condition.getBrideName() != null)
            invitationCriteria.add(Restrictions.like("bridename", "%"+condition.getBrideName()+"%"));

        if(condition.getBrideGroom() != null)
            invitationCriteria.add(Restrictions.like("bridegroom", "%"+condition.getBrideGroom()+"%"));

        if(condition.getWeddingpartyplace() != null)
            invitationCriteria.add(Restrictions.like("weddingpartyplace", "%"+condition.getWeddingpartyplace()+"%"));

        if(condition.getWeddingplace() != null)
            invitationCriteria.add(Restrictions.like("weddingplace", "%"+condition.getWeddingplace()+"%"));
        
   
        if(condition.getProduct() != null)
        {
        	Criteria productCriteria = null;
        	productCriteria = criteria.createCriteria("productCollection");
        	productCriteria.add(Restrictions.like("code", "%"+condition.getProduct()+"%"));
        }

        if(condition.getSalesmanResponsible() != null)
        {
            criteria.createCriteria("responsible").add(Restrictions.eq("id", condition.getSalesmanResponsible().getId()));
        }

        if(!condition.getStatus().isEmpty())
            criteria.add(Restrictions.in("status", condition.getStatus()));
        
        if(!condition.getAdditionalStatus().isEmpty())
            criteria.add(Restrictions.in("additionalStatus", condition.getAdditionalStatus()));

        return (List<Order>)criteria.list();
    }

    @Transactional
    public void removeOrder(Order order) throws SystemException
    {
       entityManager.remove(order);
    }

    @Transactional
    public void removeInvitation(Invitation invitationEntity) throws SystemException
    {
    	entityManager.remove(invitationEntity);
    }

    @Transactional
    public void removeInsertion(Insertion insertion) throws SystemException
    {
    	entityManager.remove(insertion);
    }
    
    @Transactional
    public void removeComment(Comment comment) throws SystemException
    {
    	entityManager.remove(comment);
    }
    
    @Transactional
    public void removePayment(Payment payment) throws SystemException
    {
    	entityManager.remove(payment);
    }
    
    
    @Transactional
    public void removeProduct(Product product) throws SystemException
    {
    	entityManager.remove(product);
    }
    
    @Transactional
    public void saveProduct(Product product, Order order) throws SystemException
    {
    	if(product.isInserted())
    		entityManager.merge(product);
    	else
    		entityManager.persist(product);
    	
    	if(!order.getProductCollection().contains(product))
    		order.getProductCollection().add(product);
    }

    @Transactional
    public void removeVigniette(Vigniette vigniette) throws SystemException
    {
            entityManager.remove(vigniette);
    }
   
    @Transactional
    public void removeAttachment(Attachment attachment) throws SystemException
    {
    	Attachment attachmentToRemove = entityManager.getReference(Attachment.class, attachment.getId());
        entityManager.remove(attachmentToRemove);
    }

    @Transactional
    public Comment saveComment(Comment comment, Order order) throws SystemException
    {    	
    	if(comment.isInserted())
    		entityManager.merge(comment);
    	else
    		entityManager.persist(comment);
    	
        if(!order.getCommentList().contains(comment))
        	order.getCommentList().add(comment);

        return comment;
    }
    
    @Transactional
    public Payment savePayment(Payment payment, Order ordr) throws SystemException
    {
    	if(payment.isInserted())
    		entityManager.merge(payment);
    	else
    		entityManager.persist(payment);

        return payment;
    }
    
    public void changeOfferToOrder(Order ordr) throws SystemException
    {
    	String newOrderNote = "To zamowienie powstalo z oferty: " + ordr.getNumber();
    	Order newOrder = null;
		newOrder = CloneUtil.cloneOrder(ordr);
		newOrder.setNumber("B");
		newOrder.setType(RecordTypeEnum.ORDER);
		newOrder = saveOrder(newOrder);
		
		String oldOrderNote = "Wygenerowano zamówienie " + newOrder.getNumber() + " z tej oferty";
		
		Comment oldOrderComment = new Comment(null, ordr, ordr.getResponsible(),new Date(),oldOrderNote);
		Comment newOrderComment = new Comment(null, newOrder, newOrder.getResponsible(),new Date(),newOrderNote);
		
		saveComment(oldOrderComment, ordr);
		saveComment(newOrderComment, newOrder);
		
		ordr.getCommentList().add(oldOrderComment);
		newOrder.getCommentList().add(newOrderComment);
		
    }
    
    public String findMaxOrderNumberByPattern(String number, Date date){
    	
    	Query findMaxOrderNumberByPattern = entityManager.createNamedQuery("findMaxOrderNumberByPattern");
		findMaxOrderNumberByPattern.setParameter("number", number);
    	findMaxOrderNumberByPattern.setParameter("date", date);
    	return (String) findMaxOrderNumberByPattern.getSingleResult();
    }
}
